﻿#region License statement
// NJamb, a specification and delta-specification DSL
// Copyright (c) 2010-2011, Mark Knell
// Published under the MIT License; all other rights reserved
#endregion

#region using...
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using NJamb.NUnit;
using NJamb.Parser.SpecificationBuilders.SubjectHas.Simple.Enumerable.Quantifiers;
using NJamb.Parser.SubjectBuilders;
using NJamb.Specifications.Simple.Enumerable;
using NUnit.Framework;
using Stile.Patterns.SelfDescribingPredicates;
#endregion

namespace NJamb.Tests.Specifications.Simple.Enumerable
{
    [TestFixture]
    public class EnumerableQuantifiedHasExtensionsAcceptanceTests : EvaluatingSampleFixture
    {
        [Test]
        public void AtLeast()
        {
            // arrange
            Expression<Func<int, bool>> predicate = x => x < 3;
            Assert.That(_sample.IntEnumerable.Count(predicate.Compile()), Is.EqualTo(1), "precondition");

            // act
            IEnumerableSpecification<IEnumerable<int>, int> enumerableSpecification =
                Specify.For(() => _sample).ThatTheSequence(x => x.IntEnumerable).Has.AtLeast(4).ItemsSatisfying(predicate);

            // assert
            IEvaluation<IEnumerable<int>> evaluation = enumerableSpecification.Evaluate();
            AssertEvaluationFailed(evaluation,
                "expected _sample.IntEnumerable would have at least 4 items satisfying x => x < 3" + Environment.NewLine
                + " but had 1 such item.");
        }

        [Test]
        public void AtMost()
        {
            // arrange
            Expression<Func<int, bool>> predicate = x => x > 3;
            Assert.That(_sample.IntEnumerable.Count(predicate.Compile()), Is.EqualTo(3), "precondition");

            // act
            IEnumerableSpecification<IEnumerable<int>, int> enumerableSpecification =
                Specify.For(() => _sample).ThatTheSequence(x => x.IntEnumerable).Has.AtMost(2).ItemsSatisfying(predicate);

            // assert
            IEvaluation<IEnumerable<int>> evaluation = enumerableSpecification.Evaluate();
            AssertEvaluationFailed(evaluation,
                "expected _sample.IntEnumerable would have at most 2 items satisfying x => x > 3" + Environment.NewLine
                + " but had 3 such items.");
        }

        [Test]
        public void Exactly()
        {
            // arrange
            Expression<Func<int, bool>> predicate = x => x <= 3;
            Assert.That(_sample.IntEnumerable.Count(predicate.Compile()), Is.EqualTo(2), "precondition");

            // act
            IEnumerableSpecification<IEnumerable<int>, int> enumerableSpecification =
                Specify.For(() => _sample).ThatTheSequence(x => x.IntEnumerable).Has.Exactly(3).ItemsSatisfying(predicate);

            // assert
            IEvaluation<IEnumerable<int>> evaluation = enumerableSpecification.Evaluate();
            AssertEvaluationFailed(evaluation,
                "expected _sample.IntEnumerable would have exactly 3 items satisfying x => x <= 3" + Environment.NewLine
                + " but had 2 such items.");
        }

        [Test]
        public void FewerThan()
        {
            // arrange
            Expression<Func<int, bool>> predicate = x => x <= 3;
            Assert.That(_sample.IntEnumerable.Count(predicate.Compile()), Is.EqualTo(2), "precondition");

            // act
            IEnumerableSpecification<IEnumerable<int>, int> enumerableSpecification =
                Specify.For(() => _sample).ThatTheSequence(x => x.IntEnumerable).Has.FewerThan(2).ItemsSatisfying(predicate);

            // assert
            IEvaluation<IEnumerable<int>> evaluation = enumerableSpecification.Evaluate();
            AssertEvaluationFailed(evaluation,
                "expected _sample.IntEnumerable would have fewer than 2 items satisfying x => x <= 3" + Environment.NewLine
                + " but had 2 such items.");
        }

        [Test]
        public void MoreThan()
        {
            // arrange
            Expression<Func<int, bool>> predicate = x => x <= 3;
            Assert.That(_sample.IntEnumerable.Count(predicate.Compile()), Is.EqualTo(2), "precondition");

            // act
            IEnumerableSpecification<IEnumerable<int>, int> enumerableSpecification =
                Specify.For(() => _sample).ThatTheSequence(x => x.IntEnumerable).Has.MoreThan(2).ItemsSatisfying(predicate);

            // assert
            IEvaluation<IEnumerable<int>> evaluation = enumerableSpecification.Evaluate();
            AssertEvaluationFailed(evaluation,
                "expected _sample.IntEnumerable would have more than 2 items satisfying x => x <= 3" + Environment.NewLine
                + " but had 2 such items.");
        }

        protected override void SetupComplete()
        {
            _sample.AddToEnumerable(5, 4, 6, 1, 3);
        }
    }
}
